import { useState } from 'react';
import { flushSync } from 'react-dom';
import './App.css';

function App() {
  console.log('render app')

  /*
    const [state, dispatch] = useState(initData)
    state：定义的数据源，可视作一个函数组件内部的变量，但只在首次渲染被创造。
    dispatch：改变state的函数，推动函数渲染的渲染函数。dispatch有两种情况-非函数和和函数。
    initData：state的初始值，initData有两种情况-非函数和和函数。
  */
  
  const [count, setCount] = useState(0);
  const [user, setUser] = useState(() => {
    return {
      name: 'zhangsan',
      age: 20
    }
  })
  const [list, setList] = useState([1,2,3])

  const content = <h1>Vite + React</h1>;
  const handleChangeCount = () => {
    // 更新是异步的，多次操作合并批量更新，最后只更新一次
    // 状态更新在 React 中是异步且可能被批量处理的
    /**
     * 前三次调用 setCount(count + 1)：

      这三次调用都是基于当前的 count 值进行的，因为它们都是直接读取当前的 count 状态值并加1。
      由于这些调用是异步的，并且 React 可能会将它们合并成一次更新，所以最终 count 只会增加1次，而不是3次。
     */
    setCount(count + 1);
    setCount(count + 1);
    setCount(count + 1);

    /**
     * 第四次调用 setCount(count => { ... })：

      这次调用使用了函数形式的状态更新，它接收当前的 count 值作为参数。
      这种方式确保每次调用都会基于最新的状态值进行更新，因此这次调用会正确地将 count 再增加1。
     */
    // setCount(count => {
    //   console.log(count, 'count')
    //   return count + 1
    // })

    // 最终的结果是 count 会增加2次，而不是4次。
  };

  const handleChangeCount1 = () => {
    /**
     * 函数形式的状态更新：使用函数形式的状态更新（setCount(prevCount => { ... })）可以确 保每次调用都会基于最新的状态值进行更新，而不会因为异步更新导致状态丢失。
      批量更新：尽管 setCount 被调用了三次，但 React 会将这些状态更新批量处理，并在一次渲染中完成所有更新。因此，组件只会重新渲染一次，而不是三次。
     */
    /**
     * react18 之后，setCount(count + 1)，setCount(count + 1)，setCount(count + 1)，会被合并成一个setCount(count + 3)
     * react18 之前，setCount(count + 1)，setCount(count + 1)，setCount(count + 1)，会被拆分为三个setCount(count + 1)
     */
    setCount(prevCount => {
      console.log(prevCount, 'prevCount')
      return prevCount + 1
    })
    setCount(prevCount => prevCount + 1)
    setCount(prevCount => prevCount + 1)
  };

  const handleChangeCount2 = () => {
    /**
     * 异步更新：setCount 是异步的，React 可能会将多次状态更新合并成一次更新。
        状态合并：由于 setCount 是基于当前的 count 值进行的，而不是基于最新的状态值，React 会将这三次更新合并成一次更新。
     */
    setTimeout(() => {
      setCount(count + 1);
      setCount(count + 1);
      setCount(count + 1);
    });
  };

  const handleChangeCount3 = () => {
    // flushSync：强制更新，立即更新，不会合并更新
    /**
     功能：
      flushSync 是 react-dom 模块中的一个函数，用于强制同步更新状态。
      它确保在函数调用期间的所有状态更新都立即应用并渲染到 DOM 中，不会被 React 的批量更新机制合并。

    使用场景：
      当你需要立即看到状态更新的效果时，例如在用户交互中需要即时反馈。
      通常用于处理一些需要立即更新 UI 的场景，如表单输入、按钮点击等。
     */
    flushSync(() => {
      setCount(count + 1);
      setCount(count + 1);
      setCount(count + 1);
    });
    flushSync(() => {
      setCount(prevCount => prevCount + 1);
      setCount(prevCount => prevCount + 1);
      setCount(prevCount => prevCount + 1);
    });
  };

  const handleUser = () => {
     // 触发更新机制，重新执行渲染App
    setUser({
      ...user,
      age: 22
    })
  }

  const handleList = () => {
    // 不可以直接修改list
    // 引用类型，地址没有发生变化，浏览器检测不到
    // list.push(4)
    // setList(list)

    setList([...list, 4])
  }
  return (
    <>
      {content}
      <div className='card'>
        <span style={{marginRight: 20}}>count is {count}</span>
        <button onClick={handleChangeCount}>直接修改Count</button>
        <button onClick={handleChangeCount1}>函数修改Count</button>
        <button onClick={handleChangeCount2}>定时器修改Count</button>
        <button onClick={handleChangeCount3}>flushSync强制更新</button>
      </div>
      <div>
        <span>名字：{user.name}</span>
        <span style={{marginLeft: 20}}>年龄：{user.age}</span>
        <button onClick={handleUser}>change user</button>
      </div>
      <div>
        {
          list.map(val => (
            <div key={val}>{val}</div>
          ))
        }
        <button onClick={handleList}>add list</button>
      </div>
    </>
  );
}

export default App;
